package com.adtec.base.cloud.server.gateway.jwt.controller;


import com.adtec.base.cloud.server.gateway.exception.AjaxResponse;
import com.adtec.base.cloud.server.gateway.exception.CustomException;
import com.adtec.base.cloud.server.gateway.exception.CustomExceptionType;
import com.adtec.base.cloud.server.gateway.filter.jpa.GlobalLog;
import com.adtec.base.cloud.server.gateway.filter.jpa.GlobalLogRepository;
import com.adtec.base.cloud.server.gateway.filter.utils.GetIpAddressUtil;
import com.adtec.base.cloud.server.gateway.jwt.jpa.SysUser;
import com.adtec.base.cloud.server.gateway.jwt.jpa.SysUserRepository;
import com.adtec.base.cloud.server.gateway.jwt.model.JwtProperties;
import com.adtec.base.cloud.server.gateway.jwt.utils.JWTConstants;
import com.adtec.base.cloud.server.gateway.jwt.utils.JwtTokenUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * JWT获取令牌和刷新令牌接口
 */
@RestController
@ConditionalOnProperty(name = "adtec.gateway.jwt.useDefaultController", havingValue = "true")
public class JwtAuthController {

    @Resource
    private JwtProperties jwtProperties;
    @Resource
    private SysUserRepository sysUserRepository;
    @Resource
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private GlobalLogRepository globalLogRepository;

    /**
     * 使用用户名密码换JWT令牌
     */
    @RequestMapping(value = JWTConstants.CONTROLLER_AUTHENTICATION)
    public Mono<AjaxResponse> authentication(@RequestBody Map<String, String> map, ServerWebExchange exchange) {

        //从请求体中获取用户名密码
        String username = map.get(jwtProperties.getUserParamName());
        String password = map.get(jwtProperties.getPwdParamName());
        GlobalLog globalLog = new GlobalLog();
        globalLog.setUrl(JWTConstants.CONTROLLER_AUTHENTICATION);
        globalLog.setMethod("POST");
        globalLog.setUsername(username);
        globalLog.setCreateTime(LocalDateTime.now());

        ServerHttpRequest request = exchange.getRequest();
        GetIpAddressUtil getIpAddressUtil = new GetIpAddressUtil();
        String ipAddress = getIpAddressUtil.getIpAddress(request);
        globalLog.setAddress(ipAddress);
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            return buildErrorResponse("用户名或者密码不能为空");
        }
        //根据用户名（用户Id）去数据库查找该用户
        SysUser sysUser = sysUserRepository.findByUsername(username);
        if (sysUser != null) {
            //将数据库的加密密码与用户明文密码match
            boolean isAuthenticated = passwordEncoder.matches(password, sysUser.getPassword());
            if (isAuthenticated) { //如果匹配成功
                globalLog.setStatus("200");
                globalLog.setResponseResult("登陆成功");
                globalLogRepository.save(globalLog);
                return buildSuccessResponse(jwtTokenUtil.generateToken(username, null));
            } else { //如果密码匹配失败
                globalLog.setStatus("403");
                globalLog.setResponseResult("登陆失败");
                globalLogRepository.save(globalLog);
                return buildErrorResponse("请确定您输入的用户名或密码是否正确！");
            }
        } else {
            globalLog.setStatus("403");
            globalLog.setResponseResult("登陆失败");
            globalLogRepository.save(globalLog);
            return buildErrorResponse("请确定您输入的用户名或密码是否正确！");
        }
    }

    /**
     * 刷新JWT令牌,用旧的令牌换新的令牌
     */
    @RequestMapping(value = JWTConstants.CONTROLLER_REFRESH)
    public Mono<AjaxResponse> refreshtoken(@RequestHeader("${adtec.gateway.jwt.header}") String oldToken) {
        if (!jwtTokenUtil.isTokenExpired(oldToken)) {
            return buildSuccessResponse(jwtTokenUtil.refreshToken(oldToken));
        }
        return buildErrorResponse("token已失效!");
//        return Mono.empty();
    }

    private Mono<AjaxResponse> buildErrorResponse(String message) {
        return Mono.create(callback -> callback.success( //请求结果成功的回调
                AjaxResponse.error( //响应信息是Error的,携带异常信息返回
                        new CustomException(CustomExceptionType.USER_INPUT_ERROR, message))));
    }

    private Mono<AjaxResponse> buildSuccessResponse(Object data) {
        return Mono.create(callback -> callback.success( //请求结果成功的回调
                AjaxResponse.success(data)  //成功响应,携带数据返回
        ));
    }

}
